package myenum.enumerated;

import net.mindview.util.Generator;
import net.mindview.util.TextFile;

import java.util.EnumMap;
import java.util.Iterator;

import static myenum.enumerated.Input.*;
import static net.mindview.util.Print.print;
import static net.mindview.util.Print.printnb;

enum Category {
    /**
     * 金钱
     */
    MONEY(NICKEL, DIME, QUARTER, DOLLAR),
    /**
     * 项目选择
     */
    ITEM_SELECTION(TOOTHPASTE, CHIPS, SODA, SOAP),
    /**
     * 退出交易
     */
    QUIT_TRANSACTION(ABORT_TRANSACTION),

    /**
     * 关闭
     */
    SHUT_DOWN(STOP);

    private Input[] values;

    Category(Input... types) {
        values = types;
    }

    private static EnumMap<Input, Category> categories = new EnumMap<Input, Category>(Input.class);

    static {
        for (Category c : Category.class.getEnumConstants()) {
            for (Input type : c.values) {
                categories.put(type, c);
            }
        }
    }

    public static Category categorze(Input input) {
        return categories.get(input);
    }
}

public class VendingMachine {
    private static State state = State.RESTING;
    private static int amount = 0;
    private static Input selection = null;

    //Tagging enum
    enum StateDuration {
        /**
         * 短暂的
         */
        TRANSIENT
    }

    enum State {

        /**
         *休眠的
         */
        RESTING {
            @Override
            void next(Input input){
                switch (Category.categorze(input)){
                    case MONEY:
                        amount += input.amout();
                        state = ADDING_MONEY;
                        break;
                    case SHUT_DOWN:
                        state = TERMINAL;
                    default:
                }
            }
        },

        /**
         * 加钱
         */
        ADDING_MONEY{
            @Override
            void next(Input input){
                switch (Category.categorze(input)){
                    case MONEY:
                        amount += input.amout();
                        state = ADDING_MONEY;
                        break;
                    case ITEM_SELECTION:
                        selection = input;
                        if(amount < selection.amout()){
                            print("Insufficient money for " + selection);
                        }else {
                            state = DISPENSING;
                        }
                        break;
                    case QUIT_TRANSACTION:
                        state = GIVING_CHANGE;
                        break;
                    case SHUT_DOWN:
                        state = TERMINAL;
                    default:
                }
            }
        },

        /**
         * 发放
         */
        DISPENSING(StateDuration.TRANSIENT){
            @Override
            void next(){
               print("here is your " + selection);
               amount -= selection.amout();
               state = GIVING_CHANGE;
            }
        },

        /**
         * 给予改变
         */
        GIVING_CHANGE(StateDuration.TRANSIENT){
            @Override
            void next(){
                if(amount > 0){
                    print("Your change: " + amount);
                    amount = 0;
                }
                state = RESTING;
            }
        },
        /**
         * 终点站
         */
        TERMINAL{
            @Override
            void output(){
                print("Halted");
            }
        }
        ;
        private boolean isTransient = false;

        State() {
        }

        State(StateDuration trans) {
            isTransient = true;
        }

        void next(Input input) {
            throw new RuntimeException("Only call next(Input input) for non-transient states");
        }

        void next() {
            throw new RuntimeException("Only call next() for StateDuration.TRANSIENT states");
        }

        void output() {
            print(amount);
        }
    }
    static void run(Generator<Input> gen){
        while (state != State.TERMINAL){
            Input input = gen.next();
            state.next(input);
            while (state.isTransient){
                state.next();
            }
            state.output();
        }
    }

    public static void main(String[] args) {
        Generator<Input> gen = new RandomInputGenerator();
        if(args.length == 1){
            gen = new FileInputGenerator(args[0]);
        }
        run(gen);
    }
}

// For a basic sanity check
class RandomInputGenerator implements Generator<Input>{

    @Override
    public Input next() {
        return Input.randomSelection();
    }
}

// Craete input from a file of ";" -separated strings:
class FileInputGenerator implements Generator<Input>{
    private Iterator<String> input;
    public FileInputGenerator(String fileName){
        input = new TextFile(fileName,";").iterator();
    }
    @Override
    public Input next() {
        if(!input.hasNext()){
            return null;
        }
        return Enum.valueOf(Input.class,input.next().trim());
    }
}